/*
 *  Copyright (c) 2022 ZhuHai Jieli Technology Co.,Ltd.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include "crc16.h"
#include "cpu.h"

static u8 crc_busy = 0;
static u8 enc_key_mode = 0xff;
static u32 sfc_enc_key;
static u32 efuse_key;
static int mutex;

int __crc16_mutex_init(void)
{
    os_mutex_create(&mutex);
    return 0;
}

u16 CRC16(const void *ptr, u32 len)
{
    u16 ret;
    u8 *p = (u8 *)ptr;

    os_mutex_pend(&mutex, 0);

    JL_CRC->REG = 0;
    while (len--) {
        JL_CRC->FIFO = *p++;
    }
    __asm_csync();
    ret = JL_CRC->REG;

    os_mutex_post(&mutex);

    return ret;
}

u32 crc_get_32bit(const char *src)
{
    const char *buf1 = src;
    u32 crc;

    JL_CRC->REG = 0;
    do {
        char c = *src++;
        JL_CRC->FIFO = c;
    } while (*src != 0);

    __asm__ volatile("csync");
    crc = JL_CRC->REG;

    JL_CRC->REG = 0;
    do {
        char c = *src--;
        JL_CRC->FIFO = c;
    } while ((u32)buf1 != (u32)src);

    __asm__ volatile("csync");
    crc |= JL_CRC->REG << 16;

    return  crc;
}

u16 crc_get_16bit(const void *src, u32 len)
{
    u8 *p = (u8 *)src;
    u16 ret;
    CPU_CRITICAL_ENTER();
    JL_CRC->REG = 0;

    while (len--) {
        JL_CRC->FIFO = *p++;
    }
    __asm__ volatile("csync");
    ret = JL_CRC->REG;
    CPU_CRITICAL_EXIT();

    return ret;
}
/* i_val: CRC校验初值 */
u16 CRC16_with_initval(const void *ptr, u32 len, u16 i_val)
{
    u16 ret;
    u8 *p = (u8 *)ptr;

    os_mutex_pend(&mutex, 0);

    JL_CRC->REG = i_val;
    while (len--) {
        JL_CRC->FIFO = *p++;
    }
    __asm_csync();
    ret = JL_CRC->REG;

    os_mutex_post(&mutex);

    return ret;
}

void init_enc_key(u8 cmd)
{
    if (enc_key_mode != cmd) {
        if (cmd) {
            if (JL_SFC->CON) { // SFC模式下不能够动ENC_KEY
                sfc_enc_key = efuse_key;
            } else {
                JL_SFCENC->KEY = efuse_key;
            }
        } else {
            if (JL_SFC->CON) {
                sfc_enc_key = 0xffff;
            } else {
                JL_SFCENC->KEY = 0xffff;
            }
        }
        enc_key_mode = cmd;
    }
}

u32 get_sfc_enc_key(void)
{
    return sfc_enc_key;
}
